home *** CD-ROM | disk | FTP | other *** search
/ Aminet 51 / Aminet 51 (2002)(GTI - Schatztruhe)[!][Oct 2002].iso / Aminet / util / arc / xadmasterdev.lha / xad / Sources / tools / xadUnTar.c < prev   
Encoding:
C/C++ Source or Header  |  2002-08-20  |  27.6 KB  |  962 lines

  1. #define NAME         "xadUnTar"
  2. #define DISTRIBUTION "(Freeware) "
  3. #define REVISION     "7"
  4. #define DATE         "12.08.2001"
  5.  
  6. /* Programmheader
  7.  
  8.     Name:        xadUnTar
  9.     Author:        SDI
  10.     Distribution:    Freeware
  11.     Description:    dearchives tar archives (also gzipped, bzipped, compressed)
  12.     Compileropts:    -
  13.     Linkeropts:    -gsi -l amiga
  14.  
  15.  1.0   06.11.00 : first version, based on xadUnFile.c
  16.  1.1   17.12.00 : added fix for octtonum
  17.  1.2   31.03.01 : handles empty file correct now
  18.  1.3   06.05.01 : now first tries for tar and afterwards for XAD type
  19.  1.4   24.05.01 : lots of bug fixes, added support for name extension blocks
  20.  1.5   27.05.01 : listing links works now as expected
  21.  1.6   01.07.01 : added second longname type.
  22.  1.7   12.08.01 : added devices and pipes
  23. */
  24.  
  25. #include <proto/xadmaster.h>
  26. #include <proto/exec.h>
  27. #include <proto/dos.h>
  28. #include <exec/memory.h>
  29. #include <dos/dosasl.h>
  30. #include <utility/hooks.h>
  31. #include "SDI_version.h"
  32. #include "SDI_compiler.h"
  33. #define SDI_TO_ANSI
  34. #include "SDI_ASM_STD_protos.h"
  35.  
  36. struct xadMasterBase *    xadMasterBase = 0;
  37. struct DosLibrary *     DOSBase = 0;
  38. struct ExecBase *     SysBase  = 0;
  39.  
  40. #define MINPRINTSIZE    51200    /* 50KB */
  41. #define NAMEBUFSIZE    512
  42. #define PATBUFSIZE    (NAMEBUFSIZE*2+10)
  43.  
  44. #define PARAM    "FROM/A,DEST=DESTDIR,PASSWORD/K,FILE/M,"    \
  45.         "NAMESIZE/K/N,FFS=OFS/S,SFS/S,"            \
  46.         "INFO=LIST/S,Q=QUIET/S,AM=ASKMAKEDIR/S,"    \
  47.         "OW=OVERWRITE/S,NA=NOABS/S,ND=NODATE/S,"    \
  48.         "NE=NOEXTERN/S,NKP=NOKILLPART/S,NP=NOPROT/S,"    \
  49.         "NT=NOTREE/S,SHORTNAME/S"
  50.  
  51. #define OPTIONS \
  52.   "FROM       The input archive file (no patterns allowed)\n"        \
  53.   "DESTDIR    The destination directory, not needed with INFO\n"    \
  54.   "PASSWORD   A password for encrypted archives\n"            \
  55.   "FILE       Filename(s) (with patterns) to be extracted\n"        \
  56.   "NAMESIZE   Names with more characters result in rename request\n"    \
  57.   "FFS=OFS    Sets NAMESIZE to 30\n"                    \
  58.   "SFS        Sets NAMESIZE to 100\n"                    \
  59.   "INFO       Shows archive information without extracting\n"        \
  60.   "QUIET      Turns of progress report and user interaction\n"        \
  61.   "ASKMAKEDIR You get asked before a directory is created\n"        \
  62.   "OVERWRITE  Files are overwritten without asking\n"            \
  63.   "NOABS      Do not extract absolute path name parts\n"        \
  64.   "NODATE     Creation date information gets not extracted\n"        \
  65.   "NOEXTERN   Turns off usage of external clients\n"            \
  66.   "NOKILLPART Do not delete partial or corrupt output files.\n"        \
  67.   "NOPROT     Protection information gets not extracted\n"        \
  68.   "NOTREE     Files are extracted without subdirectories\n"        \
  69.   "SHORTNAME  Do not display path in progress report\n"
  70.  
  71. struct xHookArgs {
  72.   STRPTR name;
  73.   ULONG size;
  74.   ULONG flags;
  75.   ULONG lastprint;
  76.   ULONG shortname;
  77. };
  78.  
  79. struct Args {
  80.   STRPTR   from;
  81.   STRPTR   destdir;
  82.   STRPTR   password;
  83.   STRPTR * file;
  84.   LONG *   namesize;
  85.   ULONG    ffs;
  86.   ULONG       sfs;
  87.   ULONG    info;
  88.   ULONG    quiet;
  89.   ULONG    askmakedir;
  90.   ULONG    overwrite;
  91.   ULONG    noabs;
  92.   ULONG    nodate;
  93.   ULONG    noextern;
  94.   ULONG       nokillpart;
  95.   ULONG    noprot;
  96.   ULONG    notree;
  97.   ULONG    shortname;
  98.  
  99.   /* parameter, no ReadArgs part */
  100.   ULONG    directrun;
  101.   ULONG    printerr;
  102.   ULONG    numextract;
  103. };
  104.  
  105. struct TarHeader
  106. {                /* byte offset */
  107.   UBYTE th_Name[100];        /*   0 */
  108.   UBYTE th_Mode[8];        /* 100 */
  109.   UBYTE th_UserID[8];        /* 108 */
  110.   UBYTE th_GroupID[8];        /* 116 */
  111.   UBYTE th_Size[12];        /* 124 */
  112.   UBYTE th_MTime[12];        /* 136 */
  113.   UBYTE th_Checksum[8];     /* 148 */
  114.   UBYTE th_Typeflag;        /* 156 */
  115.   UBYTE th_LinkName[100];    /* 157 */
  116.   UBYTE th_Magic[6];        /* 257 */
  117.   UBYTE th_Version[2];        /* 263 */
  118.   UBYTE th_UserName[32];    /* 265 */
  119.   UBYTE th_GroupName[32];    /* 297 */
  120.   UBYTE th_DevMajor[8];     /* 329 */
  121.   UBYTE th_DevMinor[8];     /* 337 */
  122.   UBYTE th_Prefix[155];     /* 345 */
  123.   UBYTE th_Pad[12];        /* 500 */
  124. };
  125.  
  126. struct TarBlockInfo {
  127.   struct Args *        Args;
  128.   struct xadArchiveInfo *ArchiveInfo;
  129.   UBYTE            Block[512];
  130.   UBYTE                 LongName[512*2];
  131.   struct TarHeader    Header;
  132.   ULONG            CurSize;
  133.   ULONG            NumFile;
  134.   ULONG            NumDir;
  135.   ULONG                 NumSpecial;
  136.   LONG            NeedToSkip; /* bytes */
  137.   LONG            NeedToSave; /* bytes */
  138.   LONG                  EndBytes;
  139.   struct Hook        Hook;
  140.   struct xHookArgs    HookArgs;
  141.   UBYTE                 Filename[NAMEBUFSIZE];
  142.   UBYTE                 EndMode;
  143.   UBYTE                 LongLinkMode;
  144.   UBYTE                 LongNameMode;
  145. };
  146.  
  147. /* Values used in Typeflag field.  */
  148. #define TF_FILE     '0'  /* Regular file */
  149. #define TF_AFILE    '\0' /* Regular file */
  150. #define TF_LINK     '1'  /* Link */
  151. #define TF_SYM        '2'  /* Reserved - but GNU tar uses this for links... */
  152. #define TF_CHAR     '3'  /* Character special */
  153. #define TF_BLOCK    '4'  /* Block special */
  154. #define TF_DIR        '5'  /* Drawer */
  155. #define TF_FIFO     '6'  /* FIFO special */
  156. #define TF_CONT     '7'  /* Reserved */
  157. #define TF_LONGNAME     'L'  /* longname block, preceedes the full block */
  158. #define TF_LONGLINK     'K'  /* longlink block, preceedes the full block */
  159.  
  160. ASM(ULONG) progrhook(REG(a0, struct Hook *), REG(a1, struct xadProgressInfo *));
  161. ASM(ULONG) workhook(REG(a0, struct Hook *), REG(a1, struct xadHookParam *));
  162. static ULONG octtonum(STRPTR oct, LONG width, LONG *ok);
  163. static BOOL checktarsum(struct TarHeader *th);
  164. static LONG handleblock(struct TarBlockInfo *t);
  165. static void ShowProt(ULONG i);
  166. static LONG CheckNameSize(STRPTR name, ULONG size);
  167. static LONG CheckName(STRPTR *pat, STRPTR name);
  168.  
  169. ULONG start(void)
  170. {
  171.   ULONG ret = RETURN_FAIL;
  172.   struct DosLibrary *dosbase;
  173.  
  174.   SysBase = (*((struct ExecBase **) 4));
  175.   { /* test for WB and reply startup-message */
  176.     struct Process *task;
  177.     if(!(task = (struct Process *) FindTask(0))->pr_CLI)
  178.     {
  179.       WaitPort(&task->pr_MsgPort);
  180.       Forbid();
  181.       ReplyMsg(GetMsg(&task->pr_MsgPort));
  182.       return RETURN_FAIL;
  183.     }
  184.   }
  185.  
  186.   if((dosbase = (struct DosLibrary *) OpenLibrary("dos.library", 37)))
  187.   {
  188.     LONG err = 0;
  189.     struct xadMasterBase *xadmasterbase;
  190.  
  191.     DOSBase = dosbase;
  192.     if((xadmasterbase = (struct xadMasterBase *)
  193.     OpenLibrary("xadmaster.library", 9)))
  194.     {
  195.       struct Args args;
  196.       struct RDArgs *rda;
  197.       
  198.       memset(&args, 0, sizeof(struct Args));
  199.       xadMasterBase = xadmasterbase;
  200.  
  201.       if((rda = (struct RDArgs *) AllocDosObject(DOS_RDARGS, 0)))
  202.       {
  203.         rda->RDA_ExtHelp = OPTIONS;
  204.  
  205.         if(ReadArgs(PARAM, (LONG *) &args, rda))
  206.         {
  207.           LONG namesize = 0;
  208.  
  209.           if(args.namesize && *args.namesize > 0)
  210.             namesize = *args.namesize;
  211.           else if(args.ffs)
  212.             namesize = 30;
  213.           else if(args.sfs)
  214.             namesize = 100;
  215.       args.namesize = &namesize;
  216.  
  217.       if(args.destdir || args.info)
  218.       {
  219.         struct xadArchiveInfo *ai;
  220.  
  221.         if((ai = (struct xadArchiveInfo *) xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  222.         {
  223.           struct Hook outhook;
  224.           struct xadFileInfo *fi;
  225.  
  226.           memset(&outhook, 0, sizeof(struct Hook));
  227.           outhook.h_Entry = (ULONG (*)()) workhook;
  228.           outhook.h_Data = &args;
  229.  
  230.           args.directrun = 1;
  231.               /* Try as normal archive (plain tar). */
  232.           if(!(err = xadGetHookAccess(ai, XAD_OUTHOOK, &outhook, XAD_INFILENAME, args.from, TAG_DONE)))
  233.           {
  234.             err = xadHookAccess(XADAC_COPY, ai->xai_InSize, 0, ai);
  235.                 xadFreeHookAccess(ai, err ? XAD_WASERROR : TAG_DONE, err, TAG_DONE);
  236.           }
  237.  
  238.           if(!args.numextract && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  239.           {
  240.             args.directrun = 0;
  241.             if(!(err = xadGetInfo(ai, XAD_INFILENAME, args.from, XAD_NOEXTERN, args.noextern,
  242.             args.password ? XAD_PASSWORD : TAG_IGNORE, args.password, TAG_DONE)))
  243.             {
  244.               fi = ai->xai_FileInfo;
  245.  
  246.               if(fi && ai->xai_Client->xc_Identifier != XADCID_TAR)
  247.                     err = xadFileUnArc(ai, XAD_OUTHOOK, &outhook, XAD_ENTRYNUMBER, fi->xfi_EntryNumber, TAG_DONE);
  248.                   xadFreeInfo(ai);
  249.                 }
  250.               }
  251.  
  252.               if(!args.numextract)
  253.                 ret = RETURN_FAIL;
  254.               else if(err)
  255.                 ret = RETURN_ERROR;
  256.               else
  257.                 ret = 0;
  258.  
  259.           xadFreeObjectA(ai, 0);
  260.             } /* xadAllocObject */
  261.           }
  262.           else
  263.             SetIoErr(ERROR_REQUIRED_ARG_MISSING);
  264.  
  265.           FreeArgs(rda);
  266.         } /* ReadArgs */
  267.         FreeDosObject(DOS_RDARGS, rda);
  268.       } /* AllocDosObject */
  269.  
  270.       if(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)
  271.         SetIoErr(ERROR_BREAK);
  272.  
  273.       if(!args.quiet)
  274.       {
  275.         if(err && !args.printerr)
  276.       Printf("\r\033[KAn error occured: %s\n", xadGetErrorText(err));
  277.         else if(ret)
  278.           PrintFault(IoErr(), 0);
  279.       }
  280.  
  281.       CloseLibrary((struct Library *) xadmasterbase);
  282.     } /* OpenLibrary xadmaster */
  283.     else
  284.       Printf("Could not open xadmaster.library\n");
  285.     CloseLibrary((struct Library *) dosbase);
  286.   } /* OpenLibrary dos */
  287.   return ret;
  288. }
  289.  
  290. static ULONG octtonum(STRPTR oct, LONG width, LONG *ok)
  291. {
  292.   ULONG i = 0;
  293.  
  294.   while(*oct == ' ' && width--)
  295.     ++oct;
  296.  
  297.   if(!*oct)
  298.     *ok = 0;
  299.   else
  300.   {
  301.     while(width-- && *oct >= '0' && *oct <= '7')
  302.      i = (i*8)+*(oct++)-'0';
  303.  
  304.     while(*oct == ' ' && width--)
  305.       ++oct;
  306.  
  307.     if(width > 0 && *oct)    /* an error, set error flag */
  308.       *ok = 0;
  309.   }
  310.  
  311.   return i;
  312. }
  313.  
  314. static BOOL checktarsum(struct TarHeader *th)
  315. {
  316.   LONG sc, i;
  317.   ULONG uc, checks;
  318.   
  319.   i = 1;
  320.   checks = octtonum(th->th_Checksum, 8, &i);
  321.   if(!i)
  322.     return 0;
  323.  
  324.   for(i = sc = uc = 0; i < 512; ++i)
  325.   {
  326.     sc += ((BYTE *) th)[i];
  327.     uc += ((UBYTE *) th)[i];
  328.   }
  329.   
  330.   for(i = 148; i < 156; ++i)
  331.   {
  332.     sc -= ((BYTE *) th)[i];
  333.     uc -= ((UBYTE *) th)[i];
  334.   }
  335.   sc += 8 * ' ';
  336.   uc += 8 * ' ';
  337.   
  338.   if(checks != uc && checks != (ULONG) sc)
  339.     return 0;
  340.   return 1;
  341. }
  342.  
  343. static void FinishFile(struct TarBlockInfo *t)
  344. {
  345.   struct DateStamp d;
  346.   LONG a, ok;
  347.  
  348.   if(!t->Args->nodate)
  349.   {
  350.     xadConvertDates(XAD_DATEUNIX, octtonum(t->Header.th_MTime, 12, &ok),
  351.     XAD_MAKELOCALDATE, 1, XAD_GETDATEDATESTAMP, &d, TAG_DONE);
  352.     SetFileDate(t->Filename, &d);
  353.   }
  354.   if(!t->Args->noprot)
  355.   {
  356.     xadConvertProtection(XAD_PROTUNIX, octtonum(t->Header.th_Mode, 8, &ok),
  357.     XAD_GETPROTAMIGA, &a, TAG_DONE);
  358.     SetProtection(t->Filename, a);
  359.   }
  360. }
  361.  
  362. static LONG handleblock(struct TarBlockInfo *t)
  363. {
  364.   LONG err = 0;
  365.  
  366.   if(t->CurSize != 512)
  367.   {
  368.     if(t->EndMode)
  369.       t->EndBytes += t->CurSize;
  370.     if(t->ArchiveInfo)
  371.     {
  372.       xadFreeHookAccess(t->ArchiveInfo, XAD_WASERROR, XADERR_INPUT, TAG_DONE);
  373.       xadFreeObjectA(t->ArchiveInfo, 0);
  374.       t->ArchiveInfo = 0;
  375.     }
  376.     if(!t->Args->info && !(SetSignal(0L,0L) & SIGBREAKF_CTRL_C))
  377.     {
  378.       if(!t->Args->directrun || t->NumFile || t->NumDir)
  379.       {
  380.         Printf("Processed");
  381.         if(t->NumFile)
  382.           Printf(" %ld file%s%s", t->NumFile, t->NumFile == 1 ? "" : "s", t->NumDir ? " and" : "");
  383.         if(t->NumDir)
  384.           Printf(" %ld director%s", t->NumDir, t->NumDir == 1 ? "y" : "ies");
  385.         if(!t->NumFile && !t->NumDir)
  386.           Printf(" nothing");
  387.         Printf(".\n");
  388.         if(t->EndBytes)
  389.           Printf("There are %ld additional tar-bytes at fileend.\n", t->EndBytes);
  390.       }
  391.     }
  392.   }
  393.   else if(t->NeedToSkip)
  394.   {
  395.     if(t->NeedToSkip > 512)
  396.       t->NeedToSkip -= 512;
  397.     else
  398.       t->NeedToSkip = 0;
  399.   }
  400.   else if(t->NeedToSave)
  401.   {
  402.     if(t->LongNameMode)
  403.     {
  404.       if(t->LongNameMode == 1)
  405.         CopyMem(t->Block, t->LongName, 512);
  406.       else if(t->LongNameMode == 2)
  407.       {
  408.         CopyMem(t->Block, t->LongName+512, 511);
  409.       }
  410.       ++t->LongNameMode;
  411.       if(t->NeedToSave > 512)
  412.         t->NeedToSave -= 512;
  413.       else
  414.         t->NeedToSave = 0;
  415.     }
  416.     else if(t->NeedToSave > 512)
  417.     {
  418.       t->NeedToSave -= 512;
  419.       if((err = xadHookAccess(XADAC_WRITE, 512, t->Block, t->ArchiveInfo)))
  420.       {
  421.         xadFreeHookAccess(t->ArchiveInfo, XAD_WASERROR, err, TAG_DONE);
  422.         xadFreeObjectA(t->ArchiveInfo, 0);
  423.         t->NeedToSkip = t->NeedToSave;
  424.         t->NeedToSave = 0;
  425.         t->ArchiveInfo = 0;
  426.       }
  427.     }
  428.     else
  429.     {
  430.       err = xadHookAccess(XADAC_WRITE, t->NeedToSave, t->Block, t->ArchiveInfo);
  431.       xadFreeHookAccess(t->ArchiveInfo, err ? XAD_WASERROR : TAG_DONE, err, TAG_DONE);
  432.       xadFreeObjectA(t->ArchiveInfo, 0);
  433.       t->NeedToSave = 0;
  434.       t->ArchiveInfo = 0;
  435.       if(!err)
  436.         FinishFile(t);
  437.     }
  438.   }
  439.   else if(t->EndMode)
  440.   {
  441.     t->EndBytes += 512;
  442.   }
  443.   else /* a file header block */
  444.   {
  445.     xadCopyMem(t->Block, &t->Header, 512);
  446.  
  447.     if(t->Header.th_Name[0])
  448.     {
  449.       LONG ok, a;
  450.       STRPTR name;
  451.  
  452.       t->HookArgs.lastprint = 0;
  453.       t->HookArgs.shortname = t->Args->shortname;
  454.       ok = checktarsum(&t->Header); /* check checksum and init ok */
  455.       t->HookArgs.size = octtonum(t->Header.th_Size, 12, &ok);
  456.  
  457.       if(ok && (t->Header.th_Typeflag == TF_LONGLINK))
  458.       {
  459.         t->LongLinkMode = 1;
  460.         t->NeedToSkip = t->HookArgs.size;
  461.       }
  462.       else if(ok && (t->Header.th_Typeflag == TF_LONGNAME))
  463.       {
  464.         t->LongNameMode = 1;
  465.         t->NeedToSave = t->HookArgs.size;
  466.       }
  467.       else if(ok && (t->Header.th_Typeflag == TF_FILE || t->Header.th_Typeflag == TF_AFILE ||
  468.       t->Header.th_Typeflag == TF_DIR || t->Header.th_Typeflag == TF_SYM || t->Header.th_Typeflag == TF_LINK
  469.       || t->Header.th_Typeflag == TF_CHAR || t->Header.th_Typeflag == TF_BLOCK || t->Header.th_Typeflag == TF_FIFO))
  470.       {
  471.         if(!t->LongNameMode && t->Header.th_Prefix[0])
  472.         {
  473.           STRPTR s, u;
  474.  
  475.           name = u = t->LongName; s = t->Header.th_Prefix;
  476.           while(*s)
  477.             *(u++) = *(s++);
  478.           if(*(u-1) != '/')
  479.             *(u++) = '/';
  480.           s = t->Header.th_Name;
  481.           while(*s)
  482.             *(u++) = *(s++);
  483.           if(*(u-1) == '/')
  484.             --u;
  485.           *u = 0;
  486.         }
  487.         else
  488.         {
  489.           name = t->LongNameMode ? t->LongName : t->Header.th_Name;
  490.           t->LongNameMode = 0;
  491.         }
  492.         a = strlen(name) + 1;
  493.         if(name[a-2] == '/')
  494.         {
  495.           if(t->Header.th_Typeflag == TF_AFILE || t->Header.th_Typeflag == TF_FILE || t->Header.th_Typeflag == TF_DIR)
  496.       {
  497.             name[--a-1] = 0;
  498.             t->Header.th_Typeflag = TF_DIR;
  499.           }
  500.         }
  501.         if(t->Args->notree)
  502.           name = FilePart(name);
  503.         if(t->Args->noabs)
  504.         {
  505.           STRPTR f;
  506.       while(*name == '/' || *name == ':')
  507.             ++name;
  508.  
  509.           for(f = name; *f; ++f)
  510.             *f = (*f == ':') ? '/' : *f;
  511.         }
  512.         ++t->Args->numextract;
  513.         if(t->Args->info)
  514.         {
  515.       struct xadDate xd;
  516.  
  517.           xadConvertDates(XAD_DATEUNIX, octtonum(t->Header.th_MTime, 12, &ok),
  518.           XAD_MAKELOCALDATE, 1, XAD_GETDATEXADDATE, &xd, TAG_DONE);
  519.           xadConvertProtection(XAD_PROTUNIX, octtonum(t->Header.th_Mode, 8, &ok), XAD_GETPROTAMIGA, &a, TAG_DONE);
  520.  
  521.           if(!(t->NumFile + t->NumDir + t->NumSpecial))
  522.             Printf("Size     Date       Time     Protection       Name\n");
  523.  
  524.           if(t->Header.th_Typeflag == TF_DIR)
  525.           {
  526.             Printf("   <dir>");
  527.             ++t->NumDir;
  528.           }
  529.           else if(t->Header.th_Typeflag == TF_SYM || t->Header.th_Typeflag == TF_LINK)
  530.           {
  531.             Printf("  <link>");
  532.             ++t->NumSpecial;
  533.           }
  534.           else if(t->Header.th_Typeflag == TF_CHAR || t->Header.th_Typeflag == TF_BLOCK)
  535.           {
  536.             printf("   <dev>");
  537.             ++t->NumSpecial;
  538.           }
  539.           else if(t->Header.th_Typeflag == TF_FIFO)
  540.           {
  541.             printf("  <pipe>");
  542.             ++t->NumSpecial;
  543.           }
  544.           else
  545.           {
  546.             Printf("%8ld", t->HookArgs.size);
  547.             t->NeedToSkip = t->HookArgs.size;
  548.             ++t->NumFile;
  549.           }
  550.           Printf(" %02ld.%02ld.%04ld %02ld:%02ld:%02ld ", xd.xd_Day, xd.xd_Month, xd.xd_Year,
  551.           xd.xd_Hour, xd.xd_Minute, xd.xd_Second);
  552.           ShowProt(a);
  553.  
  554.       Printf("%s\n", t->Args->shortname ? FilePart(name): name);
  555.           if(t->Header.th_LinkName[0])
  556.         Printf("link: %s%s\n", t->Header.th_LinkName, t->LongLinkMode ? "..." : "");
  557.         }
  558.         else
  559.         {
  560.           if(!t->Args->file || CheckName(t->Args->file, name))
  561.           {
  562.             CopyMem(t->Args->destdir, t->Filename, strlen(t->Args->destdir)+1);
  563.             AddPart(t->Filename, name, NAMEBUFSIZE);
  564.             if(t->Header.th_Typeflag == TF_SYM || t->Header.th_Typeflag == TF_LINK)
  565.             {
  566.               if(!t->Args->quiet)
  567.               Printf("Skipped Link\n");
  568.               ++t->NumSpecial;
  569.             }
  570.             else if(t->Header.th_Typeflag == TF_CHAR || t->Header.th_Typeflag == TF_BLOCK)
  571.             {
  572.               if(!t->Args->quiet)
  573.               Printf("Skipped Device\n");
  574.               ++t->NumSpecial;
  575.             }
  576.             else if(t->Header.th_Typeflag == TF_FIFO)
  577.             {
  578.               if(!t->Args->quiet)
  579.               Printf("Skipped Pipe\n");
  580.               ++t->NumSpecial;
  581.             }
  582.             else if(t->Header.th_Typeflag == TF_DIR)
  583.             {
  584.               if(!t->Args->notree)
  585.           {
  586.             BPTR a;
  587.                 LONG i = 0;
  588.                 UBYTE r;
  589.             ++t->NumDir;
  590.                 while(t->Filename[i] && !err)
  591.             {
  592.                 for(;t->Filename[i] && t->Filename[i] != '/'; ++i)
  593.                     ;
  594.                   r = t->Filename[i];
  595.                 t->Filename[i] = 0;
  596.                   if((a = Lock(t->Filename, SHARED_LOCK)))
  597.                     UnLock(a);
  598.               else if((a = CreateDir(t->Filename)))
  599.                     UnLock(a);
  600.                   else
  601.                     err = 1;
  602.                   t->Filename[i++] = r;
  603.             }
  604.             if(!t->Args->quiet)
  605.             {
  606.               if(err)
  607.                 Printf("failed to create directory '%s'\n", t->Args->shortname ? FilePart(t->Filename) : t->Filename);
  608.           else
  609.             Printf("Created directory   : %s\n", t->Args->shortname ? FilePart(t->Filename) : t->Filename);
  610.         }
  611.             if(!err)
  612.             {
  613.               struct DateStamp d;
  614.               LONG a;
  615.  
  616.               if(!t->Args->nodate)
  617.               {
  618.                 xadConvertDates(XAD_DATEUNIX, octtonum(t->Header.th_MTime, 12, &ok),
  619.                 XAD_MAKELOCALDATE, 1, XAD_GETDATEDATESTAMP, &d, TAG_DONE);
  620.                 SetFileDate(t->Filename, &d);
  621.               }
  622.               if(!t->Args->noprot)
  623.               {
  624.                 xadConvertProtection(XAD_PROTUNIX, octtonum(t->Header.th_Mode, 8, &ok),
  625.                 XAD_GETPROTAMIGA, &a, TAG_DONE);
  626.                 SetProtection(t->Filename, a);
  627.               }
  628.             }
  629.           }
  630.         }
  631.         else
  632.         {
  633.           t->NeedToSave = t->HookArgs.size;
  634.           ++t->NumFile;
  635.           if(*t->Args->namesize && CheckNameSize(FilePart(t->Filename), *t->Args->namesize))
  636.             err = XADERR_BREAK;
  637.           else if((t->ArchiveInfo = xadAllocObjectA(XADOBJ_ARCHIVEINFO, 0)))
  638.           {
  639.             if((err = xadGetHookAccess(t->ArchiveInfo, XAD_OUTFILENAME, t->Filename,
  640.         XAD_MAKEDIRECTORY, !t->Args->askmakedir, XAD_OVERWRITE, t->Args->overwrite,
  641.             XAD_NOKILLPARTIAL, t->Args->nokillpart,  t->Args->quiet ? TAG_IGNORE :
  642.             XAD_PROGRESSHOOK, &t->Hook, TAG_DONE)))
  643.         {
  644.           LONG r;
  645.  
  646.           xadFreeObjectA(t->ArchiveInfo, 0);
  647.           t->ArchiveInfo = 0;
  648.  
  649.           if(err == XADERR_SKIP)
  650.             err = 0;
  651.           else
  652.           {
  653.                     Printf("An error occured. Continue? (\033[1mY\033[0m|N): ");
  654.                     Flush(Output());
  655.                     SetMode(Input(), TRUE);
  656.                     r = FGetC(Input());
  657.                     SetMode(Input(), FALSE);
  658.                     switch(r)
  659.                     {
  660.                     case 'n': case 'N': case 'q': case 'Q': break;
  661.                     default: err = 0;
  662.                     }
  663.                   }
  664.  
  665.           if(!err)
  666.           {
  667.             t->NeedToSkip = t->NeedToSave;
  668.             t->NeedToSave = 0;
  669.           }
  670.         }
  671.             else if(!t->NeedToSave)
  672.         {
  673.                   xadFreeHookAccess(t->ArchiveInfo, TAG_DONE);
  674.                   xadFreeObjectA(t->ArchiveInfo, 0);
  675.           t->ArchiveInfo = 0;
  676.                   FinishFile(t);
  677.         }
  678.           }
  679.           else
  680.                 err = XADERR_NOMEMORY;
  681.         }
  682.           }
  683.           else if(t->Header.th_Typeflag == TF_AFILE || t->Header.th_Typeflag == TF_FILE)
  684.             t->NeedToSkip = t->HookArgs.size;
  685.         }
  686.         t->LongLinkMode = 0;
  687.       }
  688.       else
  689.       {
  690.         if(!(t->NumFile + t->NumDir))
  691.         {
  692.           if(!t->Args->directrun)
  693.           {
  694.             Printf("This is no Tar file.\n");
  695.             t->Args->printerr = 1;
  696.           }
  697.         }
  698.         err = XADERR_ILLEGALDATA;
  699.       }
  700.     }
  701.     else
  702.       t->EndMode = 1;
  703.   }
  704.  
  705.   return err;
  706. }
  707.  
  708. /* Because of SAS-err, this cannot be SAVEDS */
  709. ASM(ULONG) workhook(REG(a0, struct Hook *hook),
  710. REG(a1, struct xadHookParam *hp))
  711. {
  712.   ULONG err = 0;
  713.   /* This hook gets the data and instead of saving, it calls the handleblock()
  714.   function with 512 byte blocks (tar block size). It is an XAD output hook and
  715.   used by the main routine as output. The hook structure contains an pointer
  716.   to the argument information. output seeking is not supported. */
  717.  
  718.   switch(hp->xhp_Command)
  719.   {
  720.   case XADHC_WRITE:
  721.     {
  722.       ULONG i, j, k = 0;
  723.       struct TarBlockInfo *t = (struct TarBlockInfo *) hp->xhp_PrivatePtr;
  724.  
  725.       for(j = hp->xhp_BufferSize; j && !err; j -= i)
  726.       {
  727.         if((i = 512-t->CurSize) > j)
  728.           i = j;
  729.         xadCopyMem(((STRPTR)hp->xhp_BufferPtr)+k, t->Block+t->CurSize, i);
  730.         k += i; t->CurSize += i;
  731.         if(t->CurSize == 512)
  732.         {
  733.           err = handleblock(t);
  734.           t->CurSize = 0;
  735.         }
  736.       }
  737.       hp->xhp_DataPos += hp->xhp_BufferSize;
  738.     }
  739.     break;
  740.   case XADHC_INIT:
  741.     if(!(hp->xhp_PrivatePtr = xadAllocVec(sizeof(struct TarBlockInfo), MEMF_CLEAR)))
  742.       err = XADERR_NOMEMORY;
  743.     else
  744.     {
  745.       struct TarBlockInfo *t = (struct TarBlockInfo *) hp->xhp_PrivatePtr;
  746.  
  747.       t->Args = (struct Args *) hook->h_Data;
  748.       t->Hook.h_Entry = (ULONG (*)()) progrhook;
  749.       t->Hook.h_Data = &t->HookArgs;
  750.       t->HookArgs.name = t->Filename;
  751.     }
  752.     break;
  753.   case XADHC_FREE:
  754.     if(hp->xhp_PrivatePtr)
  755.     {
  756.       handleblock((struct TarBlockInfo *) hp->xhp_PrivatePtr); /* cleanup call */
  757.       xadFreeObjectA(hp->xhp_PrivatePtr, 0);
  758.       hp->xhp_PrivatePtr = 0;
  759.     }
  760.     /* break; */
  761.   case XADHC_ABORT: /* do nothing */
  762.     break;
  763.   default: err = XADERR_NOTSUPPORTED;
  764.   }
  765.  
  766.   if(!err && ((SetSignal(0L,0L) & SIGBREAKF_CTRL_C)))
  767.     err = XADERR_BREAK;
  768.  
  769.   return err;
  770. }
  771.  
  772. ASM(ULONG) progrhook(REG(a0, struct Hook *hook),
  773. REG(a1, struct xadProgressInfo *pi))
  774. {
  775.   ULONG ret = 0;
  776.   struct xHookArgs *h;
  777.   STRPTR name;
  778.   
  779.   h = (struct xHookArgs *) (hook->h_Data);
  780.   name = h->name;
  781.  
  782.   switch(pi->xpi_Mode)
  783.   {
  784.   case XADPMODE_ASK:
  785.     ret |= ((struct xHookArgs *) (hook->h_Data))->flags;
  786.     if((pi->xpi_Status & XADPIF_OVERWRITE) && !(ret & (XADPIF_OVERWRITE|XADPIF_SKIP)))
  787.     {
  788.       LONG r;
  789.  
  790.       Printf("\r\033[KFile '%s' already exists, overwrite? (Y|A|S|\033[1mN\033[0m|Q|R): ",
  791.       pi->xpi_FileName);
  792.       Flush(Output());
  793.       SetMode(Input(), TRUE);
  794.       r = FGetC(Input());
  795.       SetMode(Input(), FALSE);
  796.       switch(r)
  797.       {
  798.       case 'a': case 'A':
  799.     ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_OVERWRITE;
  800.       case 'y': case 'Y': ret |= XADPIF_OVERWRITE; break;
  801.       default:
  802.       case 's': case 'S': ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_SKIP;
  803.       case 'n': case 'N':
  804.         ret |= XADPIF_SKIP; break;
  805.       case 'q': case 'Q': SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); break;
  806.       case 'r': case 'R':
  807.         Printf("\r\033[KEnter new (full) name for '%s':", pi->xpi_FileName);
  808.         Flush(Output());
  809.         FGets(Input(), name, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  810.         r = strlen(name);
  811.         if(name[r-1] == '\n') /* skip return character */
  812.           name[--r] = 0;
  813.         Printf("\033[1F\033[K"); /* go up one line and clear it */
  814.         if((pi->xpi_NewName = xadAllocVec(++r, MEMF_PUBLIC)))
  815.         {
  816.           while(r--)
  817.             pi->xpi_NewName[r] = name[r];
  818.           ret |= XADPIF_RENAME;
  819.         }
  820.         else
  821.           Printf("No memory to store new name\n");
  822.       }
  823.     }
  824.     if((pi->xpi_Status & XADPIF_ISDIRECTORY))
  825.     {
  826.       LONG r;
  827.  
  828.       Printf("File '%s' exists as directory, rename? (R|S|\033[1mN\033[0m|Q): ",
  829.       pi->xpi_FileName);
  830.       Flush(Output());
  831.       SetMode(Input(), TRUE);
  832.       r = FGetC(Input());
  833.       SetMode(Input(), FALSE);
  834.       switch(r)
  835.       {
  836.       case 's': case 'S': ret |= XADPIF_SKIP; break;
  837.       case 'q': case 'Q': SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); break;
  838.       case 'r': case 'R':
  839.         Printf("\r\033[KEnter new (full) name for '%s':", pi->xpi_FileName);
  840.         Flush(Output());
  841.         FGets(Input(), name, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  842.         r = strlen(name);
  843.         if(name[r-1] == '\n') /* skip return character */
  844.           name[--r] = 0;
  845.         Printf("\033[1F\033[K"); /* go up one line and clear it */
  846.         if((pi->xpi_NewName = xadAllocVec(++r, MEMF_PUBLIC)))
  847.         {
  848.           while(r--)
  849.             pi->xpi_NewName[r] = name[r];
  850.           ret |= XADPIF_RENAME;
  851.         }
  852.         else
  853.           Printf("No memory to store new name\n");
  854.       }
  855.     }
  856.     if((pi->xpi_Status & XADPIF_MAKEDIRECTORY) &&
  857.     !(ret & XADPIF_MAKEDIRECTORY))
  858.     {
  859.       Printf("\r\033[KDirectory of file '%s' does not exist, create? (Y|A|S|\033[1mN\033[0m|Q): ",
  860.       name);
  861.       Flush(Output());
  862.       SetMode(Input(), TRUE);
  863.       switch(FGetC(Input()))
  864.       {
  865.       case 'a': case 'A':
  866.     ((struct xHookArgs *) (hook->h_Data))->flags |= XADPIF_MAKEDIRECTORY;
  867.       case 'y': case 'Y': ret |= XADPIF_MAKEDIRECTORY; break;
  868.       case 'q': case 'Q': SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); break;
  869.       default:
  870.       /*case 's': case 'S': case 'n': case 'N':*/ ret |= XADPIF_SKIP; break;
  871.       }
  872.       SetMode(Input(), FALSE);
  873.     }
  874.     break;
  875.   case XADPMODE_PROGRESS:
  876.     if(pi->xpi_CurrentSize - ((struct xHookArgs *) (hook->h_Data))->lastprint >= MINPRINTSIZE)
  877.     {
  878.       Printf("\r\033[KWrote %8ld of %8ld bytes: %s",
  879.       pi->xpi_CurrentSize, ((struct xHookArgs *) (hook->h_Data))->size, h->shortname ? FilePart(name) : name);
  880.       Flush(Output());
  881.       ((struct xHookArgs *) (hook->h_Data))->lastprint = pi->xpi_CurrentSize;
  882.     }
  883.     break;
  884.   case XADPMODE_END: Printf("\r\033[KWrote %8ld bytes: %s\n", pi->xpi_CurrentSize, h->shortname ? FilePart(name) : name);
  885.     break;
  886.   case XADPMODE_ERROR: Printf("\r\033[K%s: %s\n", h->shortname ? FilePart(name) : name, xadGetErrorText(pi->xpi_Error));
  887.     break;
  888.   }
  889.  
  890.   if(!(SetSignal(0L,0L) & SIGBREAKF_CTRL_C)) /* clear ok flag */
  891.     ret |= XADPIF_OK;
  892.  
  893.   return ret;
  894. }
  895.  
  896. static void ShowProt(ULONG i)
  897. {
  898.   LONG j;
  899.   UBYTE buf[16], *b = "rwedrwedhsparwed";
  900.   
  901.   for(j = 0; j <= 11; ++j)
  902.     buf[j] = (i & (1<<(15-j))) ? b[j] : '-';
  903.   for(; j <= 15; ++j)
  904.     buf[j] = (i & (1<<(15-j))) ? '-' : b[j];
  905.  
  906.   Printf("%.16s ", buf);
  907. }
  908.  
  909. static LONG CheckNameSize(STRPTR name, ULONG size)
  910. {
  911.   LONG ret = 0;
  912.   LONG r;
  913.  
  914.   if((r = strlen(name)) > size)
  915.   {
  916.     UBYTE buf[NAMEBUFSIZE];
  917.  
  918.     Printf("\r\033[KFilename '%s' exceeds name limit of %ld by %ld, rename? (Y|\033[1mN\033[0m|Q): ", name, size, r-size);
  919.  
  920.     Flush(Output());
  921.     SetMode(Input(), TRUE);
  922.     r = FGetC(Input());
  923.     SetMode(Input(), FALSE);
  924.     switch(r)
  925.     {
  926.     case 'q': case 'Q': SetSignal(SIGBREAKF_CTRL_C, SIGBREAKF_CTRL_C); ret = 1; break;
  927.     case 'y': case 'Y':
  928.       Printf("\r\033[KEnter new name for '%s':", name);
  929.       Flush(Output());
  930.       FGets(Input(), buf, NAMEBUFSIZE-1); /* 1 byte less to correct bug before V39 */
  931.       r = strlen(buf);
  932.       if(buf[r-1] == '\n') /* skip return character */
  933.         buf[--r] = 0;
  934.       Printf("\033[1F\033[K"); /* go up one line and clear it */
  935.       if(!(ret = CheckNameSize(buf, size)))
  936.       {
  937.         for(r = 0; buf[r]; ++r)
  938.           *(name++) = buf[r];
  939.         *name = 0;
  940.       }
  941.       break;
  942.     }
  943.   }
  944.   return ret;
  945. }
  946.  
  947. /* would be better to store the pattern parse stuff and do it only once,
  948. but so it is a lot easier */
  949. static LONG CheckName(STRPTR *pat, STRPTR name)
  950. {
  951.   UBYTE buf[PATBUFSIZE];
  952.   while(*pat)
  953.   {
  954.     if(ParsePatternNoCase(*(pat++), buf, PATBUFSIZE) >= 0)
  955.     {
  956.       if(MatchPatternNoCase(buf, name))
  957.         return 1;
  958.     } /* A scan failure means no recognition, should be an error print here */
  959.   }
  960.   return 0;
  961. }
  962.